package graphics;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import kernel.stl.LineSegment;
import kernel.stl.STL;
import kernel.stl.STLConstants;
import kernel.stl.exception.InvalidConnectionException;
import kernel.stl.slicing.Slice;
import kernel.stl.slicing.regiondetection.Region;
import kernel.stl.slicing.regiondetection.RegionDetector;
import kernel.stl.slicing.regiondetection.RegionList;

/**O CanvasSlicePlotter é responsável por fazer a impressão de uma fatia em um
 * objeto do tipo Graphics2D. Qualquer objeto que utilize um Graphics2D poderá
 * ser utilizado. No caso do STL Slicing Tool, são utilizados o JFrame para 
 * plotar as fatias na tela e a interface Printable para enviar as fatias para
 * a impressora.
 *
 * @author George
 */
public class CanvasSlicePlotter extends Canvas {

    private Graphics2D g2D; //Objeto utilizado para plotar a fatia

    private Slice slice = null;
    private STL stl;
    private static final int IMAGE_WIDTH = 500;
    private static final int IMAGE_HEIGHT = 500;
    private static final int TOP_IMAGE_BORDER = 35;
    private static final int LEFT_IMAGE_BORDER = 35;
       
    private Color fillColor = Color.BLACK;
    Polygon polygon = new Polygon();
    private boolean fillSlices = true;

    public void setFillColor(Color color) {
        fillColor = color;
    }

    public boolean getFillSlices() {
        return fillSlices;
    }

    public void setFillSlices(boolean fillSlices) {
        this.fillSlices = fillSlices;
    }

    /**Gera uma cor randomica, dentre 8 opções existentes.
     * @return
     */
    public Color newRandomColor() {
        Random r = new Random();
        int n = r.nextInt(5);
        if (n == 0) {
            return Color.BLUE;
        } else if (n == 1) {
            return Color.GRAY;
        } else if (n == 2) {
            return Color.RED;
        } else if (n == 3) {
            return Color.YELLOW;
        //else if (n == 4)
        //    return Color.BLACK;
        } else if (n == 5) {
            return Color.MAGENTA;
        } else if (n == 6) {
            return Color.PINK;
        } else {
            return Color.ORANGE;
        }
    }

    /**
     * @param g
     */
    public void paint(Graphics g) {
        g2D = (Graphics2D) g;            
                
        if (this.slice == null) {
            return;
        }
        polygon = new Polygon();

        RegionDetector regionDetector = new RegionDetector(this.slice);
        RegionList regionList = new RegionList();
        try {
            regionList = regionDetector.detect(STLConstants.TOLERANCE_FOR_REGION_DETECTION);
        } catch (InvalidConnectionException ex) {
            Logger.getLogger(CanvasSlicePlotter.class.getName()).log(Level.SEVERE, null, ex);
        }

        
        for (int i = 0; i < regionList.getRegionCount(); i++) {
            Region r = regionList.getRegion(i);
            Slice s = regionList.getRegion(i).toSlice();

            if (s.getLineSegmentList().getLineSegmentCount() == 0)
                continue;
            
            LineSegment firstLine = s.getLineSegmentList().getLineSegment(0);
            
            polygon = new Polygon();
            this.g2D.setColor(this.newRandomColor());

            boolean addPointsIntoPolygon = true;
                       
            for (int j = 0; j < s.getLineSegmentList().getLineSegmentCount(); j++) {
                
                LineSegment lineSegment = s.getLineSegmentList().getLineSegment(j);
                                                
                drawLineSegment(lineSegment, j == s.getLineSegmentList().getLineSegmentCount() - 1, 
                        addPointsIntoPolygon);
            }

            if (this.getFillSlices()) {
                this.g2D.setColor(fillColor); 
                //this.g2D.setColor(newRandomColor());
                this.g2D.fillPolygon(polygon);
                this.g2D.drawPolygon(polygon);
            }
        }


    }

    /**Construtor do CanvasSlicePlotter 
     */
    public CanvasSlicePlotter() {
    }

    public void setSTL(STL stl) {
        this.stl = stl;
    }

    public void setSlice(Slice slice) {
        this.slice = slice;
    }

    public int invertYAxis(int y) {
        return IMAGE_HEIGHT - y;
    }

    private void drawLineSegment(LineSegment lineSegment,
            boolean addTwoPointsIntoPolygon, boolean addPointsIntoPolygon) {
        /*
        double stlWidth = this.stl.getSolid().getMaxX() - this.stl.getSolid().getMinX();
        double stlHeight = this.stl.getSolid().getMaxY() - this.stl.getSolid().getMinY();
        
        if (stlWidth > stlHeight) {
        stlHeight = stlWidth;
        } else {
        stlWidth = stlHeight;
        }
        double deltaX = lineSegment.getPoint1().getX() - this.stl.getSolid().getMinX();
        double deltaY = lineSegment.getPoint1().getY() - this.stl.getSolid().getMinY();
        
        int x1 = (int) Math.round(deltaX * IMAGE_WIDTH / stlWidth);
        int y1 = (int) Math.round(deltaY * IMAGE_HEIGHT / stlHeight);
        
        deltaX = lineSegment.getPoint2().getX() - this.stl.getSolid().getMinX();
        deltaY = lineSegment.getPoint2().getY() - this.stl.getSolid().getMinY();
        
        int x2 = (int) Math.round(deltaX * IMAGE_WIDTH / stlWidth);
        int y2 = (int) Math.round(deltaY * IMAGE_HEIGHT / stlHeight);
        //*/
        //*

        int x1 = (int) Math.round(lineSegment.getPoint1().getX());
        int y1 = (int) Math.round(lineSegment.getPoint1().getY());
        int x2 = (int) Math.round(lineSegment.getPoint2().getX());
        int y2 = (int) Math.round(lineSegment.getPoint2().getY());
        //*/   

        y1 = invertYAxis(y1);
        y2 = invertYAxis(y2);

        x1 = x1 + LEFT_IMAGE_BORDER;
        y1 = y1 + TOP_IMAGE_BORDER;
        x2 = x2 + LEFT_IMAGE_BORDER;
        y2 = y2 + TOP_IMAGE_BORDER;
        
        double width = this.stl.getSolid().getMaxX() - this.stl.getSolid().getMinX();
        double height = this.stl.getSolid().getMaxY() - this.stl.getSolid().getMinY();
                
        int xOffset = 0;
        int yOffset = 0;
        
        if (width > height) {
            yOffset = (int) Math.round(((width - height) / width) * (IMAGE_WIDTH) / 2);                        
        }
        else 
            xOffset = (int) Math.round(((height - width) / height) * (IMAGE_HEIGHT) / 2);

        x1 = x1 + xOffset;
        x2 = x2 + xOffset;
        y1 = y1 - yOffset;
        y2 = y2 - yOffset;
        
        if (addPointsIntoPolygon) {
            polygon.addPoint(x1, y1);

            if (addTwoPointsIntoPolygon) {
                polygon.addPoint(x2, y2);
            }
        }
        this.g2D.setColor(this.newRandomColor());
        this.g2D.setColor(Color.BLACK);
        this.g2D.drawLine(x1, y1, x2, y2);
    }
}
